package com.service.impl;

import com.constant.AppConstant;
import com.dto.VersionDto;
import com.entity.*;
import com.exception.ParamException;
import com.repository.*;
import com.service.VersionService;
import com.utils.*;
import com.vo.ProjectVo;
import com.vo.VersionVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.io.File;
import java.io.FileInputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Stream;

/**
 * @author Yadasu
 * @date 2021/1/25 16:18
 */
@Service
@Slf4j
public class VersionServiceImpl implements VersionService {
    @Autowired
    private SysDeployHistoryRepository sysDeployHistoryRepository;
    @Autowired
    private SysVersionRepository sysVersionRepository;

    @Autowired
    private SysHistoryAndPackageVersionRepository sysHistoryAndPackageVersionRepository;

    @Autowired
    private SysServerRepository serverRepository;

    @Autowired
    private SysServerAndPackageVersionRepository sysServerAndPackageVersionRepository;

    @Autowired
    private LocalStorageRepository localStorageRepository;

    private OpenSSHClient scpclient;

    /**
     * 检测是否需要更新
     *
     * @param versionVo
     * @return
     */
    @Override
    public boolean updateVersion(VersionVo versionVo) {

        SysVersionManage sysVersionManage = new SysVersionManage();
        sysVersionManage.setPackageVersion(versionVo.getVersion());
        sysVersionManage.setPackageName(versionVo.getName());
        Example<SysVersionManage> example = Example.of(sysVersionManage);
        Optional<SysVersionManage> one = sysVersionRepository.findOne(example);

        if (one.isPresent()) {
            SysHistoryAndPackageVersion byDeployId = sysHistoryAndPackageVersionRepository.findByDeployId(one.get().getDeployId());
            if (sysDeployHistoryRepository.findById(byDeployId.getHistoryId()).isPresent()) {
                if (one.get().getPackageVersion().equals(one.get().getCurrentVersion())) {
                    if (sysDeployHistoryRepository.findById(byDeployId.getHistoryId()).get().getDeployDate().before(one.get().getUpdatedTime())) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return true;
                }
            } else {
                throw new ParamException("请查证后再检索！");
            }
        } else {
            return true;
        }

    }

    /**
     * 项目信息渲染例如：部署人，更新时间，部署时间...
     *
     * @return
     */
    @Override
    public List<VersionDto> findAll() {

        //TODO:需求将已部署未部署需要更新不需要更新的所有项目信息以dto的输出
        List<SysVersionManage> manages = sysVersionRepository.findAll();
        List<VersionDto> versionDtos = new ArrayList<>();
        for (SysVersionManage sysVersionManage : manages) {
            if (sysVersionManage.getSysDeployHistory() != null) {
                Date deployDate = sysVersionManage.getSysDeployHistory().getDeployDate();
                Date updatedTime = sysVersionManage.getUpdatedTime();
                VersionDto versionDto = new VersionDto();


                if (sysVersionManage.getPackageVersion().equals(sysVersionManage.getCurrentVersion())) {
                    if (updatedTime != null && deployDate.before(updatedTime)) {
                        versionDto.setUpdate(!AppConstant.DEFAULT_FLAG);
                    } else {
                        versionDto.setUpdate(AppConstant.DEFAULT_FLAG);
                    }
                } else {
                    versionDto.setUpdate(!AppConstant.DEFAULT_FLAG);
                }
                versionDto.setAppName(sysVersionManage.getPackageName());
                versionDto.setDeployId(sysVersionManage.getDeployId());
                versionDto.setAppDeploymentTime(sysVersionManage.getSysDeployHistory().getDeployDate());
                versionDto.setAppVersion(sysVersionManage.getPackageVersion());
                versionDto.setAppFileName(sysVersionManage.getFileName());
                versionDto.setAppCurrentVersion(sysVersionManage.getCurrentVersion());
                versionDto.setAppUpdateTime(sysVersionManage.getUpdatedTime());
                versionDto.setAppRemoteDevelopment(!AppConstant.DEFAULT_FLAG);
                versionDto.setAppCreateTime(sysVersionManage.getCreatedTime());
                versionDto.setAppOwner(sysVersionManage.getCreateBy());
                versionDtos.add(versionDto);
            } else {
                VersionDto versionDto = new VersionDto();
                versionDto.setUpdate(AppConstant.DEFAULT_FLAG);
                versionDto.setAppName(sysVersionManage.getPackageName());
                versionDto.setDeployId(sysVersionManage.getDeployId());
                versionDto.setAppFileName(sysVersionManage.getFileName());
                versionDto.setAppVersion(sysVersionManage.getPackageVersion());
                versionDto.setAppCurrentVersion(sysVersionManage.getCurrentVersion());
                versionDto.setAppUpdateTime(sysVersionManage.getUpdatedTime());
                versionDto.setAppRemoteDevelopment(AppConstant.DEFAULT_FLAG);
                versionDto.setAppCreateTime(sysVersionManage.getCreatedTime());
                versionDto.setAppOwner(sysVersionManage.getCreateBy());
                versionDtos.add(versionDto);
            }
        }
        return versionDtos;
    }

    /**
     * 新增项目信息
     *
     * @param projectVo
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public SysServerAndPackageVersion addProject(ProjectVo projectVo) {

        SysVersionManage sysVersionManage = new SysVersionManage();
        sysVersionManage.setPackageName(projectVo.getProjectName());
        Example<SysVersionManage> example = Example.of(sysVersionManage);
        Optional<SysVersionManage> one = sysVersionRepository.findOne(example);
        if (one.isPresent()) {
            throw new ParamException("已存在项目请查证");
        } else {
            sysVersionManage.setPackageVersion(projectVo.getProjectVersion());
            sysVersionManage.setCurrentVersion(projectVo.getProjectVersion());
            sysVersionManage.setCreatedTime(projectVo.getProjectCreateTime());
            sysVersionManage.setCreateBy(projectVo.getProjectOwner());
            sysVersionManage.setStatus(AppConstant.DEFAULT_STATUS);
            sysVersionManage.setUrl(AppConstant.DEFAULT_SAVE_PATH);
            sysVersionManage.setRemoteDevelopment(AppConstant.DEFAULT_REMOTE_DEVELOPMENT_STATUS);
            sysVersionRepository.save(sysVersionManage);
            SysVersionManage versionPackage = sysVersionRepository.findByPackageNameAndPackageVersion(projectVo.getProjectName(), projectVo.getProjectVersion());
            SysServerAndPackageVersion sysServerAndPackageVersion = new SysServerAndPackageVersion();
            sysServerAndPackageVersion.setDeployId(versionPackage.getDeployId());
            sysServerAndPackageVersion.setServerId(Integer.valueOf(projectVo.getProjectServerNo()));
            return sysServerAndPackageVersionRepository.save(sysServerAndPackageVersion);
        }
    }


    /**
     * 平台手动远程更新
     *
     * @param versionVo
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean windowsTriggerUpdateVersion(VersionVo versionVo) {

        SysVersionManage sysVersionManage = new SysVersionManage();
        sysVersionManage.setCurrentVersion(versionVo.getVersion());
        sysVersionManage.setPackageName(versionVo.getName());
        Example<SysVersionManage> example = Example.of(sysVersionManage);
        Optional<SysVersionManage> one = sysVersionRepository.findOne(example);
        if (one.isPresent()) {
            SysVersionManage byPackageName = sysVersionRepository.findByPackageName(versionVo.getName());
            SysServerAndPackageVersion byDeployId = sysServerAndPackageVersionRepository.findByDeployIdInServer(byPackageName.getDeployId());
            try {
                if (serverRepository.findById(byDeployId.getServerId()).isPresent()) {
                    scpclient = new OpenSSHClient(
                            serverRepository.findById(byDeployId.getServerId()).get().getServerIp(),
                            serverRepository.findById(byDeployId.getServerId()).get().getServerPort(),
                            serverRepository.findById(byDeployId.getServerId()).get().getServerUserName(),
                            serverRepository.findById(byDeployId.getServerId()).get().getServerPassword());
                    scpclient.putFile(AppConstant.DEFAULT_COMMAND_WINDOWS, AppConstant.DEFAULT_SCRIPT_NAME, AppConstant.DEFAULT_SAVE_FOLDER, null);
                    scpclient.putFile(localStorageRepository.findLocalStorageByRealName(versionVo.getRealName()).getPath(),versionVo.getRealName(),AppConstant.DEFAULT_SAVE_FOLDER,null);
                    scpclient.execCommand(AppConstant.DEFAULT_COMMAND_WINDOWS);
                    if (sysDeployHistoryRepository.findByAppName(versionVo.getName()) > 0 && sysVersionRepository.getByAppName(one.get().getCurrentVersion(), one.get().getDeployId(), versionVo.getUsername()) > 0) {
                        log.info("更新成功");
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
                //异常情况不更新
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 客户端手动更新
     *
     * @param versionVo
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean windowsClientUpdate(VersionVo versionVo) {

//        SysVersionManage byPackageNameAndPackageVersion = sysVersionRepository.findByPackageNameAndPackageVersion(versionVo.getName(), versionVo.getVersion());

        SysVersionManage sysVersionManage = new SysVersionManage();
        sysVersionManage.setCurrentVersion(versionVo.getVersion());
        sysVersionManage.setPackageName(versionVo.getName());
        Example<SysVersionManage> example = Example.of(sysVersionManage);
        Optional<SysVersionManage> one = sysVersionRepository.findOne(example);

        if (one.isPresent()) {
            if (!StringUtils.isEmpty(one.get())) {
                SysServerAndPackageVersion byDeployId = sysServerAndPackageVersionRepository.findByDeployIdInServer(one.get().getDeployId());
                try {
                    if (serverRepository.findById(byDeployId.getServerId()).isPresent()) {
                        scpclient = new OpenSSHClient(
                                serverRepository.findById(byDeployId.getServerId()).get().getServerIp(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPort(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerUserName(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPassword());

                        scpclient.putFile(AppConstant.DEFAULT_COMMAND_WINDOWS, AppConstant.DEFAULT_SCRIPT_NAME, AppConstant.DEFAULT_SAVE_FOLDER, null);
                        scpclient.putFile(localStorageRepository.findLocalStorageByRealName(versionVo.getRealName()).getPath(),versionVo.getRealName(),AppConstant.DEFAULT_SAVE_FOLDER,null);
                        scpclient.execCommand(AppConstant.DEFAULT_COMMAND_WINDOWS);
                        if (sysDeployHistoryRepository.findByAppName(versionVo.getName()) > 0 && sysVersionRepository.getByAppName(one.get().getCurrentVersion(), one.get().getDeployId(), versionVo.getUsername()) > 0) {
                            log.info("更新成功");
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        throw new ParamException("请查证后再检索！");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    //异常情况不更新
                    return false;
                }
            } else {
                SysVersionManage byPackageName = sysVersionRepository.findByPackageName(versionVo.getName());
                SysServerAndPackageVersion byDeployId = sysServerAndPackageVersionRepository.findByDeployIdInServer(byPackageName.getDeployId());
                try {
                    if (serverRepository.findById(byDeployId.getServerId()).isPresent()) {
                        scpclient = new OpenSSHClient(
                                serverRepository.findById(byDeployId.getServerId()).get().getServerIp(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPort(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerUserName(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPassword());

                        scpclient.putFile(AppConstant.DEFAULT_COMMAND_WINDOWS, AppConstant.DEFAULT_SCRIPT_NAME, AppConstant.DEFAULT_SAVE_FOLDER, null);
                        scpclient.putFile(localStorageRepository.findLocalStorageByRealName(versionVo.getRealName()).getPath(),versionVo.getRealName(),AppConstant.DEFAULT_SAVE_FOLDER,null);
                        scpclient.execCommand(AppConstant.DEFAULT_COMMAND_WINDOWS);
                        if (sysDeployHistoryRepository.findByAppName(versionVo.getName()) > 0 && sysVersionRepository.getByAppName(one.get().getCurrentVersion(), one.get().getDeployId(), versionVo.getUsername()) > 0) {
                            log.info("更新成功");
                            return true;
                        } else {
                            return false;
                        }
                    } else {
                        throw new ParamException("请查证后再检索！");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    //异常情况不更新
                    return false;
                }
            }
        } else {
            return false;
        }

    }

    /**
     * 一次部署
     *
     * @param projectVo 项目相关信息
     * @return
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean windowsClientAdd(ProjectVo projectVo) {
        SysVersionManage sysVersionManage = new SysVersionManage();
        sysVersionManage.setPackageName(projectVo.getProjectName());
        Example<SysVersionManage> example = Example.of(sysVersionManage);
        Optional<SysVersionManage> one = sysVersionRepository.findOne(example);
        if (one.isPresent()) {
            SysHistoryAndPackageVersion byDeployIdAndHistoryId = sysHistoryAndPackageVersionRepository.findByDeployId(one.get().getDeployId());
            if (byDeployIdAndHistoryId != null) {
                throw new ParamException("已存在部署请作更新处理！");
            } else {
                SysDeployHistory sysDeployHistory = new SysDeployHistory();
                SysHistoryAndPackageVersion packageVersion = new SysHistoryAndPackageVersion();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                Date date = new Date();
                try {
                    sysDeployHistory.setDeployDate(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(sdf.format(date)));
                    sysDeployHistory.setAppName(projectVo.getProjectName());
                    sysDeployHistory.setDeployUser(projectVo.getProjectOwner());
                    SysDeployHistory save = sysDeployHistoryRepository.save(sysDeployHistory);
                    packageVersion.setDeployId(one.get().getDeployId());
                    packageVersion.setHistoryId(save.getId());
                    sysHistoryAndPackageVersionRepository.save(packageVersion);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                SysServerAndPackageVersion byDeployId = sysServerAndPackageVersionRepository.findByDeployIdInServer(one.get().getDeployId());
                try {
                    if (serverRepository.findById(byDeployId.getServerId()).isPresent()) {
                        scpclient = new OpenSSHClient(
                                serverRepository.findById(byDeployId.getServerId()).get().getServerIp(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPort(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerUserName(),
                                serverRepository.findById(byDeployId.getServerId()).get().getServerPassword());
                        scpclient.putFile(AppConstant.DEFAULT_COMMAND_WINDOWS, AppConstant.DEFAULT_SCRIPT_NAME, AppConstant.DEFAULT_SAVE_FOLDER, null);
                        scpclient.putFile(localStorageRepository.findLocalStorageByRealName(projectVo.getProjectFileName()).getPath(),projectVo.getProjectFileName(),AppConstant.DEFAULT_SAVE_FOLDER,null);
                        scpclient.execCommand(AppConstant.DEFAULT_COMMAND_WINDOWS);
                        if (sysDeployHistoryRepository.findByAppName(projectVo.getProjectName()) > 0 && sysVersionRepository.getByAppName(one.get().getCurrentVersion(), one.get().getDeployId(), projectVo.getUsername()) > 0) {
                            log.info("更新成功");
                            return true;
                        } else {
                            return false;
                        }

                    } else {
                        throw new ParamException("请查证后再检索！");
                    }
                } catch (Exception e) {
                    //异常情况不更新
                    throw new ParamException(e.getMessage());
                }
            }
        } else {
            throw new ParamException("部署失败!，请选择后再进行部署！");
        }

    }


}
